﻿#include "com_rs232.h"
#include "qdebug.h"
#include "gpio_info.h"

#include <topo_info.h>


QMap<int, TOPO_NODE *>  test_node;
UINT test_online[8];
int test_count;

void create_test_data()
{
    test_node.clear();

    int cnt = qrand() % 10+2;
    test_count = cnt;
    QList <int> valid_id;
    memset(test_online, 0, 8 * sizeof(UINT));
    for ( int i =0; i < cnt; i ++)
    {
        int n = qrand() % 254 + 1;
        test_online[n/32] |= (1<<(n%32));

        valid_id.append(n);
    }


    for ( int i = 0; i < valid_id.count(); i++)
    {
        // if ( test_online[i/32] &(1<<i%32))
        {
            TOPO_NODE * node = new TOPO_NODE;
            node->_id = valid_id[i];

            TOPO_PHY * phy_1 = new TOPO_PHY( node->_id ,0 );
            phy_1->target = new TOPO_PHY( valid_id[ (i-1 + cnt)% cnt], 1);
            node->phy[0] = phy_1;

            TOPO_PHY * phy_2 = new TOPO_PHY(  node->_id, 1 );
            phy_2->target = new TOPO_PHY( valid_id[(i+1 + cnt) % cnt], 0);
            node->phy[1] = phy_2;


            test_node[node-> _id] = node;
        }
    }
}

rs232com::rs232com(QString com, QObject* parent)
    : QObject{ parent } ,
    com_name(com),
    myCom(nullptr)
{
}

bool rs232com::openPort(QString portName, BaudRateType BaudRate, DataBitsType DataBit, ParityType Parity, StopBitsType StopBit)
{
    com_name = portName;
    if(myCom == NULL)
    {
#if 0
#ifdef Q_OS_WIN//如果是windows系统
        myCom = new QextSerialPort(com_name);
#else
        myCom = new QextSerialPort("/dev/" + com_name);
#endif
#else
        myCom = new QextSerialPort(com_name);
#endif
    }

    myCom->setTimeout(1000);

    if (myCom->isOpen())
        return true;
    qDebug() << "++++++++++++++++++++++++++++++++++++++++++++";
    qDebug() << "Option on device: " << myCom->portName();
    qDebug() << "++++++++++++++++++++++++++++++++++++++++++++";
    if (myCom->open(QIODevice::ReadWrite))
    {
        //清空缓冲区
        myCom->flush();
        //设置波特率
        myCom->setBaudRate(BaudRate);
        //设置数据位
        myCom->setDataBits(DataBit);
        //设置校验位
        myCom->setParity(Parity);
        //设置停止位
        myCom->setStopBits(StopBit);
        myCom->setFlowControl(FLOW_OFF);
        myCom->setTimeout(10);

        return true;
    }
    QString str =QString("串口 %1 打开失败!").arg(portName) ;

    mHelper::ShowMessageBoxError(str);
    return false;

}

void rs232com::close_port()
{
    if (myCom)
        myCom->close();
}

bool rs232com::read_com_data()
{
    m_dataCom.clear();

    QByteArray data;
    const int nMax = 64 * 1024;
    int timeout = 100;
    // while (myCom->bytesAvailable() <= 0)  mHelper::mSleep(10);
    while( timeout-->0)//for (;;)
    {
        data = myCom->readAll(); //读取串口数据
        if (data.isEmpty()) {//没有读取到串口数据就退出循环
            mHelper::mSleep(1);
            continue ;
        }

        //读取到的串口数据，加入到QByteArray m_dataCom
        m_dataCom.append(data);
        if (m_dataCom.size() > nMax)
        { //防止 m_dataCom 过长
            m_dataCom = m_dataCom.right(nMax);
        }
        break;
    }

    return m_dataCom.isEmpty() == false ;
}

void rs232com::query_node_phy_target(int node_id, int phy_id)
{
#ifdef TEST
    TOPO_NODE * tmp_node = test_node[node_id];

    QByteArray    outData =   "4\r\n" ;
    m_dataCom = "4\r\n";
    m_dataCom.append(QString("%1").arg(node_id, 2, 16, QLatin1Char('0')));
    m_dataCom.append(QString("%1").arg(phy_id, 2, 16, QLatin1Char('0')));
    if (phy_id == 0)
    {
        m_dataCom.append(QString("%1").arg(tmp_node->child_1->_connect_node, 2, 16, QLatin1Char('0')));
        m_dataCom.append(QString("%1").arg(tmp_node->child_1->_connect_phy, 2, 16, QLatin1Char('0')));
    }
    else
    {
        m_dataCom.append(QString("%1").arg(tmp_node->child_2->_connect_node, 2, 16, QLatin1Char('0')));
        m_dataCom.append(QString("%1").arg(tmp_node->child_2->_connect_phy, 2, 16, QLatin1Char('0')));
    }

    m_dataCom.append("\r\n");
#else
    if (!myCom->isOpen())
    {
        bool opened=   openPort(com_name, BaudRateType::BAUD115200, DataBitsType::DATA_8, ParityType::PAR_NONE, StopBitsType::STOP_1);
        if (!opened)
            return  ;
    }

    //查询节点01
    QByteArray outData =  QString("5 %1%2%3%4 F\r\n")
                             .arg(2,2, 16, QLatin1Char('0'))
                             .arg(node_id, 2, 16, QLatin1Char('0'))
                             .arg(phy_id, 2, 16, QLatin1Char('0'))
                             .arg(0, 2, 16, QLatin1Char('0')).toLatin1() ;

    myCom->write(outData);


    if (!read_com_data() )
    {
        qDebug() << ("query_node_phy_target 失败！");
        return;
    }

    outData =   "4\r\n" ;
    myCom->write(outData);

    if (!read_com_data() )
    {
       qDebug() <<("query_node_phy_target 失败！");
        return;
    }


#endif
    QByteArrayList list = m_dataCom.split('\n' );

    if (list.count() > 1)
    {

        QString ord = list[0].trimmed();
        QString info  =  list[1].trimmed() ;
        if (ord ==outData.trimmed())
        {
            bool ok;
            int node_id = info.midRef(0, 2).toInt(&ok, 16);
            int phy_id = info.midRef(2, 2).toInt(&ok, 16);

            int taget_node = info.midRef(4, 2).toInt(&ok, 16);
            int target_phy = info.midRef(6, 2).toInt(&ok, 16);

            TOPO_NODE * node = TopoInfo::Instance()->node_map [node_id];
            node ->_id = node_id;

            TOPO_PHY * phy_1 =  new TOPO_PHY(node_id,phy_id);
            phy_1->target  =  new TOPO_PHY( taget_node,target_phy);

            node->phy[phy_id] = phy_1;

            TopoInfo::Instance()->node_map [node_id] = node;
        }
    }
}


//5   1
void rs232com::query_node_phy_info(int node_id, int phy_id)
{
#ifdef TEST
    TOPO_NODE * node_ = test_node[node_id];
    QByteArray  outData =   "4\r\n" ;

    m_dataCom =  "4\r\n" ;
    m_dataCom.append(QString("%1").arg(node_id,2, 16, QLatin1Char('0')));
    m_dataCom.append(QString("%1").arg(phy_id,2, 16, QLatin1Char('0')));
    m_dataCom.append(QString("%1").arg(2,2, 16, QLatin1Char('0')));  //???????
    m_dataCom.append(QString("%1").arg(2,2, 16, QLatin1Char('0')));  //???????
    m_dataCom.append("\r\n") ;

#else

    if (!myCom->isOpen())
    {
        bool opened=   openPort(com_name, BaudRateType::BAUD115200, DataBitsType::DATA_8, ParityType::PAR_NONE, StopBitsType::STOP_1);
        if (!opened)
            return  ;
    }

    //查询节点01
    // QByteArray outData =  QString("5 01%1%2").arg(node_id, 2, 16, QLatin1Char('0'))
    //             .arg(phy_id, 2, 16, QLatin1Char('0')) .toLatin1() ;

    QByteArray outData =  QString("5 %1%2%3%4 F\r\n")
                             .arg(1,2, 16, QLatin1Char('0'))
                             .arg(node_id, 2, 16, QLatin1Char('0'))
                             .arg(phy_id, 2, 16, QLatin1Char('0'))
                             .arg(0, 2, 16, QLatin1Char('0')).toLatin1() ;

    myCom->write(outData);

    if (!read_com_data() )
    {
        qDebug() << ("query_node_phy_info失败！");
        return;
    }

    outData =   "4\r\n" ;
    myCom->write(outData);


    read_com_data();

    if ( m_dataCom.isEmpty() )
    {
       qDebug() << ("query_node_phy_info失败！");
        return;
    }

#endif

    QByteArrayList list = m_dataCom.split('\n' );

    if (list.count() > 1)
    {

        QString ord = list[0].trimmed();
        QString info  =  list[1].trimmed() ;
        if (ord ==outData.trimmed())
        {
            bool ok;
            int node_id = info.midRef(0, 2).toInt(&ok, 16);
            int phy_id = info.midRef(2, 2).toInt(&ok, 16);

            int phy_count= info.midRef(4, 2).toInt(&ok, 16);
            int rec_count  = info.midRef(6, 2).toInt(&ok, 16);

            TOPO_NODE * node = TopoInfo::Instance()->node_map [node_id];
            node ->_id = node_id;
            // node->
            TopoInfo::Instance()->node_map [node_id] = node;
        }
    }
}



int rs232com::query_node_phy_count(int node_id)
{
#ifdef TEST
    TOPO_NODE * node_ = test_node[node_id];

    QByteArray  outData =   "4\r\n" ;

    m_dataCom = "4\r\n";
    m_dataCom.append(QString("%1").arg(node_->_id, 2, 16, QLatin1Char('0')));
    m_dataCom.append(QString("%1").arg(0, 2, 16, QLatin1Char('0')));
    m_dataCom.append(QString("%1").arg(2, 2, 16, QLatin1Char('0')));
    m_dataCom.append(QString("%1").arg(2, 2, 16, QLatin1Char('0')));
    m_dataCom .append("\r\n");

#else

    if (!myCom->isOpen())
    {
        bool opened=   openPort(com_name, BaudRateType::BAUD115200, DataBitsType::DATA_8, ParityType::PAR_NONE, StopBitsType::STOP_1);
        if (!opened)
            return 0 ;
    }

    //查询节点01  
    QByteArray outData =  QString("5 %1%2%3%4 F\r\n")
                             .arg(0,2, 16, QLatin1Char('0'))
                             .arg(node_id, 2, 16, QLatin1Char('0'))
                             .arg(0, 2, 16, QLatin1Char('0'))
                             .arg(0, 2, 16, QLatin1Char('0')).toLatin1() ;

    myCom->write(outData);

    if (!read_com_data() )

    {
       qDebug () << ("query_node_phy_count失败！");
        return 0;

    }

    outData =   "4\r\n" ;
    myCom->write(outData);

    m_dataCom.clear();

    if (!read_com_data() )

    {
        qDebug () << ("query_node_phy_count失败！");
        return 0;
    }

#endif
    QByteArrayList list = m_dataCom.split('\n' );

    if (list.count() > 1)
    {
        QString ord = list[0].trimmed();
        QString info  =  list[1].trimmed() ;
        if (ord ==outData.trimmed())
        {
            bool ok;
            int node_id = info.midRef(0, 2).toInt(&ok, 16);
            int phy_id = info.midRef(2, 2).toInt(&ok, 16);
            int phy_count= info.midRef(4, 2).toInt(&ok, 16);
            int rec_count = info.midRef(6, 2).toInt(&ok, 16);

            TOPO_NODE * node = new TOPO_NODE;
            node ->_id = node_id;
            if (phy_count>0)
                node->phy[0] = new TOPO_PHY(node_id,0);
            if (phy_count>1)
                node->phy[1] = new TOPO_PHY(node_id,1);
            // node->
            TopoInfo::Instance()->node_map [node_id] = node;
            return phy_count;
        }
    }
    return 0;
}

void rs232com::query_node_online()
{
    // #ifdef TEST
    //     // bool ok;
    //     // QString info="FFFFFFFF";
    //     // UINT node = info.toULongLong( &ok, 16 );

    //     for ( int id = 0 ; id < 8; id ++ )
    //     {
    //         INT64 node  =test_online[id];
    //       //  bool ok;
    //        // INT64 node = info.toULongLong( &ok, 16 );
    //         for ( int bit =0; bit < 32; bit ++  )
    //         {
    //             //  if ( node & ( 1<< bit))
    //             if ( (node >>  bit)&1)
    //                 TopoSetting::node_map[  bit+(id )*32] = new _NODE;
    //         }

    //     }
    // #else
    if (!myCom->isOpen())
    {
        bool opened=   openPort(com_name, BaudRateType::BAUD115200, DataBitsType::DATA_8, ParityType::PAR_NONE, StopBitsType::STOP_1);
        if (!opened)
            return  ;
    }

    for ( int id = 80; id < 88; id ++ )
    {
        QByteArray outData = QString("%1\r\n").arg(id, 0, 16).toLatin1();
#ifdef TEST

        m_dataCom = outData;
        m_dataCom.append(QString("%1").arg(test_online[id-80], 8, 16, QLatin1Char('0')));
        m_dataCom.append("\r\n");
#else
        myCom->write(outData);

        if (!read_com_data() )
        {
           qDebug() << ("query_node_online失败！");
            return;
        }
#endif
        QByteArrayList list = m_dataCom.split('\n' );
        if (list.count() > 1)
        {

            QString ord = list[0].trimmed();
            QString info  =  list[1].trimmed() ;
            if (ord ==outData.trimmed())
            {
                bool ok;
                UINT node = info.toULongLong( &ok, 16 );
                for ( int bit =0; bit < 32; bit ++  )
                {
                    //  if ( node & ( 1<< bit))
                    if ( (node >>  bit)&1)
                        TopoInfo::Instance()->node_map[  bit+(id-80)*32] = new TOPO_NODE;
                }
            }
        }
    }

    TopoInfo::Instance()->node_count = TopoInfo::Instance()->node_map.count();

}


int rs232com::query_node_count()
{
    if (!myCom->isOpen())
    {
        bool opened=   openPort(com_name, BaudRateType::BAUD115200, DataBitsType::DATA_8, ParityType::PAR_NONE, StopBitsType::STOP_1);
        if (!opened)
            return 0;
    }

    QByteArray outData = "0\r\n";
    myCom->write(outData);

    if (!read_com_data() )
    {
      //  qDebug () <<          ("query_node_count 失败！");
        return 0;
    }

    QByteArrayList list = m_dataCom.split('\n' );

    if (list.count() > 1)
    {
        QString ord = list[0].trimmed();
        QString info  =  list[1].trimmed() ;
        if (ord ==outData.trimmed())
        {
            bool ok;
            int node_count= info.midRef(4,2).toInt(&ok, 16);

            return node_count;
        }
    }
    return 0;
}
/* 寄存器  1
 * 24~31    MAC地址BYTE5
 * 16~23    MAC地址BYTE4
 * 8~15     MAC地址BYTE3
 * 0-7      MAC地址BYTE2
 * 寄存器  2
 * 24~31    MAC地址BYTE1
 * 16~23    MAC地址BYTE0
 * 0        更新MAC地址
*/
QString rs232com::query_mac_address()
{
    if (!myCom->isOpen())
    {
        bool opened=   openPort(com_name, BaudRateType::BAUD115200, DataBitsType::DATA_8, ParityType::PAR_NONE, StopBitsType::STOP_1);
        if (!opened)
            return nullptr;
    }

    QByteArray outData = "1\r\n";
    myCom->write(outData);

    if (!read_com_data() )
    {
        qDebug() << ("query_mac_address失败！");
        return "0000000";
    }

    QByteArrayList list = m_dataCom.split('\n' );
    if (list.count() > 1)
    {

        QVector <QString> mac(6);

        QString ord = list[0].trimmed();
        QString info  =  list[1].trimmed() ;
        if (ord ==outData.trimmed())
        {
            mac[3] = info.mid(6, 2);
            mac[2] = info.mid(4, 2);
            mac[1] = info.mid(2, 2);
            mac[0] = info.mid(0, 2);
        }
        outData = "2\r\n";
        myCom->write(outData);
        if (!read_com_data() )
        {
            qDebug () << ("query_mac_address失败！");
            return "00000000";
        }

        list = m_dataCom.split('\n');

        ord = list[0].trimmed();
        if (ord ==outData.trimmed())
        {
            QByteArray info =  list[1].trimmed();
            mac[4] =info.mid(0, 2);
            mac[5] =info.mid(2, 2);
        }

        mac_id = QStringList::fromVector(mac).join('-');

    }

    return mac_id;
}

/* 寄存器  3
    24-31   PHY接口数量
    16-23   当前Cmder
    8 15    当前优先级
     0-7    当前节点ID
*/
TOPO_NODE *  rs232com::query_current_node_info()
{
    //return NULL;
    if (!myCom->isOpen())
    {
        bool opened=   openPort(com_name, BaudRateType::BAUD115200, DataBitsType::DATA_8, ParityType::PAR_NONE, StopBitsType::STOP_1);
        if (!opened)
            return nullptr;
    }

    QByteArray id = "3\r\n";
    myCom->write(id);

    if (!read_com_data() )
    {
       qDebug() << ("query_node_id失败！");
        return nullptr;
    }
    QList<QByteArray> list = m_dataCom.split ( '\n');
    if (list.count() > 1)
    {
        QByteArray ord = list[0].trimmed() ;
        if (ord == id.trimmed())
        {
            QByteArray info =  list[1].trimmed();
            bool ok;
            node_id = info.mid(6, 2).toInt(&ok, 16);
            TOPO_NODE * node ;
            if (  TopoInfo::Instance()->node_map.contains(node_id) == false)
            {
                node = new TOPO_NODE;
            }
            else
                node= TopoInfo::Instance()->node_map[node_id];

            node->_id =  info.mid(6, 2).toInt(&ok, 16);
            int phy_cnt = info.mid(0, 2).toInt(&ok, 16);
            if (phy_cnt>0)
                node->phy[0] = new TOPO_PHY(node->_id ,0);
            if (phy_cnt>1)
                node->phy[1] = new TOPO_PHY(node->_id ,1);

            TopoInfo::Instance()->node_map[node->_id] = node;


            return node;

        }
    }
    return NULL;
}

void rs232com::set_mac_address(QString newmac)
{
    QByteArray outData = QString("1 %1 F\r\n").arg(newmac.left(8)).toLatin1() ;
    myCom->write(outData);

    read_com_data();



    outData = QString("2 %1").arg(newmac.mid(8)).toLocal8Bit();
    outData.append("0001 F\r\n");

    //  mHelper::mSleep(10);
    myCom->write(outData);

    read_com_data();

}

QString  rs232com:: query_gpio(int gpio_id)
{
    if (!myCom->isOpen())
    {
        bool opened=   openPort(com_name, BaudRateType::BAUD115200, DataBitsType::DATA_8, ParityType::PAR_NONE, StopBitsType::STOP_1);
        if (!opened)
            return nullptr;
    }
    QString id = QString("%1\r\n").arg(gpio_id +10,0,16);
    QByteArray outData = id.toLatin1();
    myCom->write(outData);

    if (!read_com_data() )
    {
        qDebug () << ("query_gpio失败！");
        return outData;
    }


    QList<QByteArray> list = m_dataCom.split ( '\n');
    if (list.count() > 1)
    {
        QByteArray ord = list[0].trimmed() ;
        QString info = list[1].trimmed();
        if (ord == id.trimmed())
        {
            bool ok;
            GPIO * gpio = new GPIO;

            gpio-> remote_id = info.midRef(0, 2).toInt(&ok, 16);

            gpio->remote_bit = info.midRef(2, 2).toInt(&ok, 16);

            BYTE byte3 = info.midRef(4, 2).toInt(&ok, 16);

            gpio->flip =byte3 &(1<<1) ;

            gpio-> mode_input = byte3 &(1 ) ;

            BYTE byte4 = info.midRef(6, 2).toInt(&ok, 16);

            gpio-> level = byte4 &(1<<1) ;

            gpio -> on = byte4 & 1;

            if ( GpioSetting::gpio.contains(com_name) == false)
                GpioSetting::init_gpio(com_name);
            GpioSetting::gpio[com_name][gpio_id] = gpio;
        }
    }
    return outData;
}

QByteArray rs232com::set_gpio(int gpio_id, QString  gpio_str)
{
    // QString new_gpio = QString::number(gpio);
    // QString id = QString("%1").arg(gpio_id +10,0,16);

    if( myCom && myCom->isOpen() )
    {
        QByteArray outData = QString("%1 %2 F\r\n")
                                 .arg(gpio_id +10,0,16)
                                 .arg(gpio_str ).toLatin1() ;
        myCom->write(outData);

        read_com_data();


        return outData;
    }

    return "";
}

